package vm

import (
	"kumachan/standalone/rx"
	. "kumachan/interpreter/runtime/rt"
)


type Machine struct {
	program    *Program
	options    *Options
	pool       GoroutinePool
	scheduler  rx.Scheduler
	worker1    *rx.Worker
	worker2    *rx.Worker
	GeneratedObjects
}

func (m *Machine) Call(ctx Context, f FuncValue, arg Value) Value {
	switch f := (*f).(type) {
	case UsualFunction:
		return call(ctx, m, f, arg)
	case NativeFunction:
		var h = &InteropHandle {
			context:  ctx,
			machine:  m,
			location: nil,
		}
		return f(arg, h)
	default:
		panic("invalid function value")
	}
}

func (m *Machine) GetFuncValue(sym Symbol) (FuncValue, bool) {
	var index, exists = m.GeneratedObjects.funcMap[sym]
	if exists {
		return m.functions[index], true
	} else {
		return nil, false
	}
}

func (m *Machine) EvaluateStandaloneFunctionSeed(seed FunctionSeed) FuncValue {
	return seed.Evaluate(m.funcCtx)
}

func (m *Machine) GetScheduler() rx.Scheduler {
	return m.scheduler
}

func (m *Machine) VdGetInfo() VdConf {
	return m.program.RpcConf.VdConf
}

func (m *Machine) RpcGetInfo() RpcConf {
	return m.program.RpcConf
}

func (m *Machine) VdCallAdapter(info VdAdapterInfo, x Value) Value {
	var f, exists = m.GetFuncValue(info.Symbol)
	if !(exists) { panic("something went wrong") }
	return m.Call(rx.Background(), f, x)
}

func (m *Machine) VdCallValidator(info VdValidatorInfo, x Value) bool {
	var f, exists = m.GetFuncValue(info.Symbol)
	if !(exists) { panic("something went wrong") }
	return FromBool(m.Call(rx.Background(), f, x).(EnumValue))
}


